var $ = window.$;
var jade = require('jade');
var JSON = window.JSON;
var animate = require('../../util/animate');
var event = require('../../core/event');
var slide = require('../../core/slide');
var util = require('../../util/index');
var uiUtil = require('../../util/ui');
var notify = require('../notify/ui');
var config = require('../../core/config');
var timing = require('../timing/manager');
var frac = require('../../util/frac');

var _inited = false;

var ret = {
    init: function(){
        if(_inited){
            return;
        }
        this.slideId = [];
        this.preset = {
            0 : {
                min_interval : 7,
                same_touch : 2,
                beat_align : "2:0/4"
            },
            1 : {
                min_interval : 5,
                same_touch : 2,
                beat_align : "0:0/4"
            },
            2 : {
                min_interval : 4,
                same_touch : 3,
                beat_align : "0:0/4"
            },
            3 : {
                min_interval : 2,
                same_touch : 4,
                beat_align : "0:0/4"
            },
            4 : {
                min_interval : 2,
                same_touch : 5,
                beat_align : "0:0/4,0:2/4"
            }

        };
        this.minInterval = 1050;
        this.sameTouch = 2;
        this.difficuties = config.i18n("simplify09").split(",");
        event.lock('key', 'simplify');
        _inited = true;
    },

    setManager: function (ma) {
        this.manager = ma;
    },

    onEvent: function(e, param){

    },

    loadPreset : function(id){
        var preset = this.preset[id];
        slide.setVal(this.slideId[1], preset.min_interval);
        slide.setVal(this.slideId[2], preset.same_touch);
        this.minInterval = Math.floor(preset.min_interval)*50 + 850;
        this.sameTouch = preset.same_touch;
        $("#dialog_beat_align").val(preset.beat_align);
        this.updateSlideVal();
    },

    updateSlideVal : function(){
        $("#dialog_simplify_min_interval").html(config.i18n("simplify02") + this.minInterval);
        $("#dialog_simplify_same_touch").html(config.i18n("simplify03") + this.sameTouch);
    },

    show: function(param){
        this.param = param;
        var tmpl = jade.compileFile('./tmpl/note/simplify.jade');
        var html = tmpl({config: config});
        $('#dialog_layer').append(html);

        var self = this;
        this.parent = $('#dialog_simplify');
        this.parent.on('click','.g_barhead i', function () {
            self.hide();
        });
        this.parent.on('click','.g_click', function(){
            var btn = $(this);
            var type = btn.data('type');
            var notes = self.manager.chart.note;
            var result = self.simplify(notes, {
                minInterval : self.minInterval,
                sameTouch : self.sameTouch,
                noteAlign : $("#dialog_beat_align").val()
            });
            if(type == 'close'){
                self.hide();
                notify.addNotify({msg : util.formatStr(config.i18n("simplify10"),[notes.length, result.length])});
                self.manager.chart.note = result;
            }else if(type == 'simulate'){
                notify.addNotify({msg : util.formatStr(config.i18n("simplify07"),[notes.length, result.length])});
            }
        });

        var sliders = this.parent.find('.g_slide');
        var id = slide.on({
            parent: sliders.eq(0),
            min: 0,
            max: 4,
            onchange: function(val){
                val = Math.floor(val);
                $("#dialog_simplify_difficuty").html(config.i18n("simplify01") + self.difficuties[val]);
                self.loadPreset(val);
            }
        });
        this.slideId.push(id);
        id = slide.on({
            parent: sliders.eq(1),
            min: 0,
            max: 10,
            onchange: function(val){
                self.minInterval = Math.floor(val)*50 + 850;
                self.updateSlideVal();
            }
        });
        this.slideId.push(id);
        id = slide.on({
            parent: sliders.eq(2),
            min: 1,
            max: 10,
            onchange: function(val){
                self.sameTouch = Math.floor(val);
                self.updateSlideVal();
            }
        });
        this.slideId.push(id);

        this.parent.show();
        uiUtil.dialogInc();
        animate.normalScaleIn(this.parent).then(function(){

        });
        event.trigger(event.events.global.blur);

    },

    hide: function(){
        var self = this;
        if(!this.parent){
            return;
        }
        animate.normalScaleOut(this.parent).then(function(){
            self.parent.remove();
            self.parent = null;
            uiUtil.dialogDec();
        });
        event.unlock();
        _inited = false;
    },

    parseBeatStr : function(str){
        var result = [];
        var arr1 = str.split("/");
        var arr2 = arr1[0].split(":");
        result.push(+arr2[0]);
        result.push(+arr2[1]);
        result.push(+arr1[1]);
        return result;
    },

    filterNotes : function(notes, ctx, reverse){
        var result = [];
        var pattern = {};
        var pointNumToTouch = 0;
        if(reverse){
            notes = notes.reverse();
        }
        for(var i=0;i<notes.length;i++){
            var note = notes[i];
            if(note.type == 1){
                result.push(note);
                continue;
            }
            var beat = note.beat;
            if(ctx.startBeatNum == null){
                ctx.startBeatNum = beat[0];
            }
            //Check min interval
            var pos = note.index || note.column;
            var time = timing.beatToTime(note.beat);
            if(ctx.blockNoteTime[pos]){
                if(time - ctx.blockNoteTime[pos] <ctx. minInterval){
                    continue;
                }
            }
            //Only preserve notes at certain beat divide
            if(ctx.beatReserve.length){
                var reserved = false;
                for(var j=0;j<ctx.beatReserve.length;j++){
                    var resBeat = ctx.beatReserve[j];
                    resBeat = [resBeat[0], resBeat[1], resBeat[2]];
                    var n = resBeat[0];
                    resBeat[0] = beat[0];
                    if(frac.compare(beat,resBeat) == 0 && (n == 0 || (beat[0] - ctx.startBeatNum) % n == 0)){
                        reserved = true;
                        break;
                    }
                }
                if(!reserved){
                    continue
                }
            }
            pointNumToTouch += 1;
            if(pointNumToTouch > ctx.maxSameTimeTouch){
                continue;
            }
            pattern[note.index] = 1;
            result.push(note);
        }
        return {notes:result, pattern : pattern};
    },

    simplify : function(notes, options){
        var result = [];
        var ctx = {};
        ctx.blockNoteTime = [];
        ctx.maxSameTimeTouch = options.sameTouch;
        ctx.beatReserve = options.noteAlign.split(',');
        ctx.startBeatNum = null;
        ctx.minInterval = options.minInterval;
        var groupedNotes = [];
        var currBeat = null;
        var lastPattern = null;
        var note = null;
        for(var i=0;i<ctx.beatReserve.length;i++){
            ctx.beatReserve[i] = this.parseBeatStr(ctx.beatReserve[i]);
        }

        //group notes by beat
        var tmp = [];
        for(var i=0;i<notes.length;i++) {
            note = notes[i];
            if(!currBeat){
                currBeat = note.beat;
            }else{
                if(frac.compare(currBeat,note.beat) != 0){
                    groupedNotes.push(tmp);
                    tmp = [];
                    currBeat = note.beat;
                }
            }
            tmp.push(note);
        }
        groupedNotes.push(tmp);

        //filter notes
        for(var i=0;i<groupedNotes.length;i++){
            var notes = groupedNotes[i];
            var filterResult = this.filterNotes(notes, ctx, false);
            if(filterResult.notes.length){
                var ptn = JSON.stringify(filterResult.pattern);
                if(ptn == lastPattern){
                    //if two continuous pattern are the same, try to get a new pattern by reserve filtering
                    lastPattern = null;
                    filterResult = this.filterNotes(notes, ctx, true);
                    console.log("after reverse:" + filterResult.notes.length);
                }else{
                    lastPattern = ptn;
                }
                for(var j=0;j<filterResult.notes.length;j++){
                    note = filterResult.notes[j];
                    result.push(note);
                    var pos = note.index || note.column
                    ctx.blockNoteTime[pos] = note.time;
                }
            }
        }

        return result;
    }
};

module.exports = ret;
